// java -cp /Developer/Development/personal/groovy/groovy-1.8.0/embeddable/groovy-all-1.8.0-beta-1.jar:. Splasher
// on eepc: CLASSPATH=/home/leanne/Documents/Development/groovy-1.7.4/embeddable/groovy-all-1.7.4.jar:.
//then if in /media/DURACELL/harvester2 do : java Splasher

// need to include 'all' jar in classpath before fast splash screen will work, but also seems to defeat the apple-specific features
/*
1. missing tool tips - done
2. missing blue pill buttons - done
3. work on gzip file processing
4. fix harvesterhelper dup/ver issue for zip resource
5. Loading gif message for splash screen; need a new loading.gif
*/
import groovy.swing.SwingBuilder
import java.awt.*
import java.awt.Font;
import javax.swing.*
import javax.swing.BorderFactory as BF
import java.awt.GridLayout
import javax.swing.JFileChooser
import static java.awt.GridBagConstraints.*
import java.io.*;
import java.util.*

//JFrame.setDefaultLookAndFeelDecorated(false);
//System.setProperty("apple.laf.useScreenMenuBar", "true");
//System.setProperty("com.apple.mrj.application.apple.menu.about.name", "Resource Harvester");
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

def today = new Date()
def flag = true
def userdir = java.lang.System.getProperty("user.dir")
def username = java.lang.System.getProperty("user.name")
def userhome = java.lang.System.getProperty("user.home")
def ms = new Font("Monospaced", Font.PLAIN, 10)
def ms12 = new Font("Monospaced", Font.PLAIN, 10)

// load tooltip message text from properties for default values
def mfn = 'message.properties'
File mf = new File(mfn)
def msg = new ConfigSlurper().parse(mf.toURL())


// load gui properties from prior session or make new config properties with default values
def fn = 'harvester.properties'
def config 
File fp = new File(fn)
if (fp.exists())
{
	config = new ConfigSlurper().parse(fp.toURL())
} // end of if to load properties
else
{
	java.util.Properties props = new Properties()
	props.setProperty("path.to.source", userhome);
	props.setProperty("path.to.target", userdir);
	props.setProperty("cbpa", "false");
	props.setProperty("cboa", "false");
	props.setProperty("cb1", "false");
	props.setProperty("cb2", "true");
	props.setProperty("cb3", "false");
	props.setProperty("cb4", "false");
	props.setProperty("bgis", "false");
	props.setProperty("bgih", "false");
	props.setProperty("bgie", "true");
	props.setProperty("bgos", "false");
	props.setProperty("bgoh", "false");
	props.setProperty("bgoe", "true");

	config = new ConfigSlurper().parse(props)
	config.cbpa=true	// include all
	config.cbpic=true	// ignore case of include
	config.includes = ""	// specific fragments to include
	config.bgis=false	// match fragment from start of resource name excluding path
	config.bgih=false	// match fragment with some part of resource name excluding path
	config.bgie=true	// match fragment with end of resource name excluding path

	config.cboa=true	// omit all
	config.cboic=true	// ignore case of omit
	config.omits = ""	// specific fragments to omit
	config.bgos=false	// match fragment from start of resource name excluding path
	config.bgoh=false	// match fragment with some part of resource name excluding path
	config.bgoe=true	// match fragment with end of resource name excluding path

	config.cb1=false	// Extract from Zips
	config.cb2=true		// Allow Dups in Target
	config.cb3=false	// Delete Source after Copy
	config.cb4=false	// Add further debug text into list.txt

	new FileWriter(fn).withWriter{writer ->  writer.write(config) }  // no need to close()
} // when no properties found as in first time it runs

def sourceFolder
def source

def targetFolder
def target

def jop = {msg1, msg2 -> JOptionPane.showMessageDialog(null, msg2, msg1, JOptionPane.ERROR_MESSAGE)}

/*
// =============================================
def icon = "file:///./purple1.png".toURL()
def p1 = imageIcon(icon)
icon = "file:///./red1.png".toURL()
def r1 = imageIcon(icon)
*/

/*
* ===================================================================================
* logic to make a temporary swing string, fork another groovy process to view results
* ===================================================================================
*/
def sample = { evt ->
	def ok = true
    swing.edt{swing.count.text="> "}

	// ================================================
	// confirm target is there and is a folder before we start the copy
	File f = new File(swing.target.text)
	if (!f.exists())
	{
		jop("Target Folder does Not Exist",swing.target.text)
		ok=false
	} // end of file
	else
	{
		if (!f.isDirectory())
		{
			jop("Selected Target is Not a Directory",swing.source.text)
			ok=false
		} // end of if 
	} // end of else

	// ================================================
	// confirm source is there before we start the copy
	f = new File(swing.source.text)
	if (!f.exists())
	{
		jop("Source Does Not Exist",swing.source.text)
		ok=false
	} // end of file


	// ================================================
	// confirm source is there before we start the copy
	if (ok & swing.cb1.selected & swing.cb3.selected)
	{
		jop("Cannot Remove Zip File Resources","Pls note that resources found in zip files will not be removed ")
	} // end of file


	// allow processing to continue if no errors were found in validation logic above
	if (ok)
	{
    	// copied from CrtGUI.groovy
    	swing.edt{swing.copy.setCursor (Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR))}
    	swing.edt{swing.count.text="> searching..."}  

	   //swing.exit.enabled=false  // disallow exit while copy thread running else copy swing panel will never die 
	   //swing.copy.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
	   //swing.copy.setEnabled( false );
	   //println "... set cursor to WAIT_CURSOR"

	   // update config property values to reflect latest user choices
	   config.path.to.source=swing.source.text
	   config.path.to.target=swing.target.text

	   config.cbpa=swing.cbpa.selected		// include all
	   config.cbpic=swing.cbpic.selected		// ignore case of include
	   config.bgis=swing.bgis.selected		// match fragment from start of resource name excluding path
	   config.bgih=swing.bgih.selected		// match fragment with some part of resource name excluding path
	   config.bgie=swing.bgie.selected		// match fragment with end of resource name excluding path

	   config.cboa=swing.cboa.selected		// omit all
	   config.cboic=swing.cboic.selected		// ignore case of omit
	   config.bgos=swing.bgos.selected		// match fragment from start of resource name excluding path
	   config.bgoh=swing.bgoh.selected		// match fragment with some part of resource name excluding path
	   config.bgoe=swing.bgoe.selected		// match fragment with end of resource name excluding path

	   config.cb1=swing.cb1.selected		// Extract from Zips
	   config.cb2=swing.cb2.selected		// Allow Dups in Target
	   config.cb3=swing.cb3.selected		// Delete Source after Copy
	   config.cb4=swing.cb4.selected		// Debug text


	   // compose list of included fragments ending with a semi-colon ;
	   def includes =""
	   7.times
	   {
		def ident="is${it}"; 
		if (!swing."$ident".text.equals("")) {includes+=swing."$ident".text;includes+=";"}
	   } // end of times

	   if (includes.length()<1) 
		{
			swing.cbpa.selected=true; includes=""; config.cbpa = swing.cbpa.selected;
		} // end of if

	   config.includes = includes;

	   def omits =""
	   7.times
	   {
		ident="os${it}"; 
		if (!swing."$ident".text.equals("")) {omits+=swing."$ident".text;omits+=";"}
	   } // end of times

	   if (omits.length()<1) 
		{
			swing.cboa.selected=true; omits="";  config.cboa = swing.cboa.selected;
		} // end of if

	   config.omits = omits;

	   // revise values of the config file
	   new FileWriter(fn).withWriter{writer ->  writer.write(config) }  // no need to close()

	   // how to use swingworker to do task outside the EDT ?
      	   Thread.start
	   {
  		 try
  		 {
			//println "thread started...."

			// fork new process
			command = 'groovy harvester.groovy'
			process = command.execute()
			process.waitFor() 
		    swing.edt{swing.count.text="> ${process.in.text}"}  
  		 }
		 catch(Exception e)
  		 {
			println "catching: ${e.message}"
  		 }  // reenable buttons
		 finally
		 {
			//println "... set cursor to DEFAULT_CURSOR V2"
			swing.edt{swing.copy.setCursor(Cursor.getDefaultCursor() ) }
			//swing.copy.setCursor(Cursor.getDefaultCursor())
			//swing.copy.enabled=true  // allow exit for user
			//swing.exit.enabled=true  // allow exit for user
		 }
	   }  // end of doOutside Thread start

	}  // end of if ok

	//println "... end of method"
	//swing.copy.setCursor(Cursor.getDefaultCursor())
	//swing.copy.enabled=true  // allow exit for user
	//swing.exit.enabled=true  // allow exit for user
} // end of sample

// ============================================
// text for tool tips :

// ============================================
swing = new SwingBuilder()

// ============================================
// gui actions follow :
swing.actions
{
	action(id:'quitAction', name: 'Exit', mnemonic:'x', accelerator: shortcut('x'), shortDescription: 'Quit harvesting', closure:{System.exit(0)})
} // end of actions

//Color bgColor = new Color(0xFF0000); // Use the hex number syntax==> background:bgColor, 
def frame = swing.frame(title:"Harvester", defaultCloseOperation:JFrame.EXIT_ON_CLOSE, show:false, pack:true, preferredSize: [860, 380])  
{
    gridBagLayout()
	menuBar
	{
		menu(text:'File', mnemonic: 'F')
		{
			menuItem(quitAction)
		} // end of menu
	} // end of menubar

	label(icon:imageIcon("Harvester.png"), constraints: gridBagConstraints(gridx:0, gridy:0, gridheight : 2), border: lineBorder(color:Color.BLACK, thickness:1) )
	 
	label(text:'Resource Folder :',constraints: gridBagConstraints(gridx: 1, gridy: 0)) 

	source = textField(id:'source', columns:100, text:config.path.to.source, toolTipText:msg.ttsource, constraints: gridBagConstraints(gridx: 2, gridy: 0, weighty:0.2),minimumSize:[360,30],preferredSize:[500,40],maximumSize:[600,60])  
	//focusLost:{println "source lost focus"},
	
	//icon:imageIcon(resource:'BrowseBlue.png'), 
	button(toolTipText:msg.ttsourcebrowse, constraints: gridBagConstraints(gridx: 3, gridy: 0), icon:imageIcon("blue1browse2.png"), borderPainted:false, rolloverEnabled:true, rolloverIcon:imageIcon("blue1browse1.png"), opaque:false,
	actionPerformed:
          {
	                chooser = new JFileChooser(config.path.to.source)
			        chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
        	        int returnValue = chooser.showOpenDialog();
                	if (returnValue == javax.swing.JFileChooser.APPROVE_OPTION) 
                	{  
                   		sourceFolder = chooser.getSelectedFile()
				        source.text = sourceFolder
				        //swing.copy.enabled=true
                	} // end of if
		  } // end of actionPerformed 
		) // end of button

	   // target folder gui bits
		label(text:'Target Folder   :',constraints: gridBagConstraints(gridx: 1, gridy: 1)) 
		target = textField(id:'target', columns:30, text:config.path.to.target, toolTipText:msg.tttarget,constraints: gridBagConstraints(gridx: 2, gridy: 1, weighty:0.2), minimumSize:[360,30],preferredSize:[500,40],maximumSize:[600,60])   
		//focusLost:{println "target lost focus"},
		
		button(toolTipText:msg.tttargetbrowse, constraints: gridBagConstraints(gridx: 3, gridy: 1), icon:imageIcon("blue1browse2.png"), borderPainted:false, rolloverEnabled:true, rolloverIcon:imageIcon("blue1browse1.png"), actionPerformed:
          {
	                chooser = new JFileChooser(config.path.to.target)
			        chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        	        //int returnValue = chooser.showOpenDialog();
                	//if (returnValue == javax.swing.JFileChooser.APPROVE_OPTION) 

			        if (chooser.showOpenDialog()==javax.swing.JFileChooser.APPROVE_OPTION)
                	{  
                   		targetFolder = chooser.getSelectedFile()
				        target.text = targetFolder
                	} // end of if

		  } // end of actionPerformed 
		) // end of button

    // =========================================================
	   // gui bits for the include choices
		label(text:'Include Resource Types : ',constraints: gridBagConstraints(gridx: 0, gridy: 2, weighty:0.2,weightx:0.1,anchor:LINE_END)) 
		hbox(constraints: gridBagConstraints(gridx:1, gridy: 2, gridwidth:2, weightx:0.1, anchor:LINE_START ) )
		{
    		7.times{def ident="is${it}";  ident = textField(id:"is${it}",columns:9,text:"", minimumSize:[60,30]) }  
        } // end of hbox

		is0.toolTipText=msg.ttis0

    // code to populate text fields from property file
    	def line
		int num = 0
        config.includes.split(';').toList().collect
		{
	        	line = it
    			ident="is${num++}"; 
	    		swing."$ident".text=line.trim()
        		return line
    	} // end of collect

        vbox(constraints: gridBagConstraints(gridx: 3, gridy: 2,weightx:0.1))
        {
            def cbpa = checkBox(id:"cbpa",text:"Include All",toolTipText:msg.ttcbpa, selected:config.cbpa)
		def cbpic = checkBox(id:"cbpic",text:"Ignore Case",toolTipText:msg.ttcbpic, selected:config.cbpic)
        } // end of vbox

        vbox(constraints: gridBagConstraints(gridx: 4, gridy: 2))
        {
			ButtonGroup bg = new ButtonGroup()
			radioButton(id:'bgis',text:'Start   ',buttonGroup:bg, toolTipText:msg.ttis, selected:config.bgis)
			radioButton(id:'bgih',text:'Has     ', buttonGroup:bg, toolTipText:msg.ttih, selected:config.bgih)
			radioButton(id:'bgie',text:'End',buttonGroup:bg, toolTipText:msg.ttie,selected:config.bgie)
        } // end of vbox

    // omits ===============================================
    	label(text:'   Omit Resource Types : ',constraints: gridBagConstraints(gridx: 0, gridy: 3, weighty:0.2,weightx:0.1,anchor:LINE_END)) 

		hbox(constraints: gridBagConstraints(gridx:1, gridy: 3, gridwidth:2, weightx:0.1, anchor:LINE_START) )
		{
	        7.times{def ident="os${it}"; 
	                    ident = textField(id:"os${it}", columns:9, text:"", minimumSize:[60,30])}
        } //  end of hbox
		num = 0
        config.omits.split(';').toList().collect
		{
	        	line = it
			    ident="os${num++}"; 
			    swing."$ident".text=line.trim()
        		return line
    	} // end of collect
    	
		os0.toolTipText=msg.ttos0

        vbox(constraints: gridBagConstraints(gridx: 3, gridy: 3))
        {
		    def cboa = checkBox(id:"cboa",text:"Omit None", toolTipText:msg.ttcboa, selected:config.cboa)
            def cboic = checkBox(id:"cboic", text:"Ignore Case", toolTipText:msg.ttcboic, 
            selected: config.cboic)        
        } // end of vbox

        vbox(constraints: gridBagConstraints(gridx: 4, gridy: 3))
        {
			ButtonGroup bg = new ButtonGroup()
			radioButton(id:'bgos',text:'Start   ',buttonGroup:bg, toolTipText:msg.ttos,selected:config.bgos)
			radioButton(id:'bgoh',text:'Has     ',buttonGroup:bg, toolTipText:msg.ttoh,selected:config.bgoh)
			radioButton(id:'bgoe',text:'End',buttonGroup:bg, toolTipText:msg.ttoe,selected:config.bgoe)
        } // end of vbox
    // =========================================================

    /*
		LineBorder lb = lineBorder(color:Color.GREEN, thickness:1)
	   	TitledBorder titledBorder = BorderFactory.createTitledBorder(border, "Title");
	   	panel(layout: new GridLayout(0,1),border: lineBorder(color:Color.GREEN, thickness:1), background:java.awt.Color.GREEN, constraints: gridBagConstraints(gridx: 10, gridy: 3))
    */
    
// button panel placed into south border fill:BOTH, anchor:CENTER, gridwidth:10;;background:Color.YELLOW,
	panel(constraints: gridBagConstraints(gridx: 0, gridy: 4,gridwidth:5),  border: lineBorder(color:Color.BLUE, thickness:1))
	{
    	gridLayout(rows:1)
		hbox() 
		{
    		swing.hstrut(10);

			int cbn = 0
		for (name in ["Extract from Zips", "Allow Dups in Target","Delete Resource after Copy","Verbose"]) 
{ cbn++; checkBox(id:"cb${cbn}",text:name) }
			cb1.selected=config.cb1
			cb2.selected=config.cb2
			cb3.selected=config.cb3
			cb4.selected=config.cb4
			cb1.toolTipText=msg.ttcb3
			cb2.toolTipText=msg.ttcb2
			cb3.toolTipText=msg.ttcb1
			cb4.toolTipText=msg.ttcb4
    		swing.hstrut(10);

			vbox()
			{
			    vstrut(5)
                button(id:'copy',icon:imageIcon("green1copywhite.png"), borderPainted:false, 
                rolloverEnabled:true, rolloverIcon:imageIcon("red1copy.gif"),
                actionPerformed:{ event -> 
					//swing.copy.setEnabled( false )
					//doLater{swing.copy.setCursor (Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));}
					if (flag)
					{
					    flag = false
    					doOutside{sample()}
    					flag= true
    				} // end of if 
			    }, toolTipText:msg.ttcopy)
			
    			button(id:"exit",icon:imageIcon("green1exit.png"), borderPainted:false, toolTipText:msg.ttexit,
    			rolloverEnabled:true, rolloverIcon:imageIcon("yellow1.png"), actionPerformed: { event -> System.exit(0) })
			    vstrut(5)
            } // endo of vbox

    		swing.hstrut(50);
		} // end of hbox

	} // end of panel

    label(id:'count',text:'>', constraints: gridBagConstraints(gridx: 1, gridy: 5,gridwidth:3, anchor:LINE_START, weighty:0.1))


} // end of frame

swing.lookAndFeel('system')
frame.setLocationRelativeTo(null);
//frame.getContentPane().setBackground(java.awt.Color.GREEN)
frame.show()
jop("Approach to Harvest Resources","The folder path to a resource is never used to include or omit a resource.\nOnly the resource name is used, like 'greenpasture.jpg'")


/*   == check box item changed code
def selectedText
def itemStateChanged = { evt ->
    //selectedText = (String)swing.cb0.getSelectedItem()
	println "itemStateChanged=${evt.text}"
}

code copied from thread.start
			//filename = "xxxx.groovy"
			// makeFile(filename,cf)       
			// dump current frame selection to temporary file
			// s = 'groovy '+filename      
			// create a command string to call temp demo swing .groovy script
			// println "...running command: $s"
			// proc = s.execute()
			// if (!swing.keepalive.selected) proc.waitForOrKill(16000)
			// proc.waitForOrKill(16000)   
			// thread will auto die in 16 sec.s unless user kills it early
			// def ans = proc.in.text      
			// the process may return a message which we print next 
			// println "Response from process follows:\n$ans"
			
			// Obtain status and output
            println "return code: ${ process.exitValue()}"
            println "stderr: ${process.err.text}"
            //println "stdout: ${process.in.text}" 
			//process.in.eachLine { line -> println line }
			println "---- done ----"
			//sleep(5500)
			//println "... set cursor to DEFAULT_CURSOR"


*/


